package main

import "fmt"

/**

	channel 例子五：
		接收方，接收完毕的时候，通知发送我接收完毕了！



 */

 // c 这个chan 表示数据 ， dono这个chan是同时是否接收完毕
func donWorker5(id int, c chan int, dono chan bool)  {

	for n := range c {
		fmt.Printf("编号：%d, 接收到数据：%c\n", id, n)
		// 往 dono 这个 chan 发送一个值，表示我接收完毕这个数据
		dono <- true

		// 这里可以单独开一个协程，专门发送，就不会堵塞了
		// 后面有更好的办法
		// go func() { dono <- true }()
	}

}

// 可以创建一个结构，来包装这两个chan
type worker struct {
	in chan int // chan int 表示我这个chan里面的值只能是 int
	dono chan bool // 表示是否接收完毕
}

// 创建 chan
func createWorker(id int) worker {
	// 创建 chan
	w := worker {
		in: make(chan int),
		dono: make(chan bool),
	}
	// 调用协程去接收
	go donWorker5(id, w.in, w.dono)

	return w
}

func chanDemo(){
	var workers [10]worker
	for i := 0; i< 10 ;i ++  {
		workers[i] = createWorker(i)
	}

	// 发送数据
	for i := 0; i < 10 ;i ++  {
		workers[i].in <- 'a' + i
		// <-workers[i].dono
	}

	// 发送数据
	for i := 0; i < 10 ;i ++  {
		workers[i].in <- 'A' + i
		// <-workers[i].dono
	}

	// 接收所有的done消息
	for _, worker := range workers  {
		// 这里接收两遍的原因是上面有两个 for，也就是说每一个 worker都会发送两次
		<-worker.dono
		<-worker.dono
	}

	/**

		这个时候会出现一个错误：fatal error: all goroutines are asleep - deadlock!
	    是因为我go语言channel的定义是，既然有了发送方就必须要有接收方！

		上面的这个例子是因为我第一组小写的循环开始执行，donWorker5 就开始接收通过channel传输过来的数据，
		在接收的时候，又会给发送方发送一个dono的数据，这个时候dono的数据没有地方接收，
		只有等到第二组大写循环执行完毕后才能开始接收！
		这个时候dono既然没有地方接收，那么就会堵塞掉，因为channel是一个堵塞的队列！

		有一个很简单的解决方法，就是 发送 dono的时候，在开启一个协程专门发送dono，
		go func(){dono <- true}()


	 */

}

func main() {
	chanDemo()
	
}
